% 
% @(#)real_InStream.m	1.3  3/16/88
%
import _VectorOfCharObject from "Builtins"
export _InStreamObject to "Builtins"

const _InStreamObject == immutable object _InStreamObject
  export getSignature, create
  const InStreamType == type InStreamType
    operation getChar -> [Character]
    operation unGetChar [ Character ]
    operation getString -> [ String ]
    function eos -> [Boolean]
    operation close
  end InStreamType

  function getSignature -> [ r : Signature ]
    r <- InStreamType
  end getSignature

  operation create [ fd : Integer ] -> [r : InStreamType]
    r <- object aUnixInStream
      export getChar, unGetChar, getString, eos, close
      const myfd : Integer == fd
      monitor
	var isBroken :    Boolean <- false
	const BUFSIZE == 1024
	const buffer == _VectorOfCharObject.create[BUFSIZE]
	var maxValidIndex : Integer <- ~1
	var minValidIndex : Integer <- 0
	var isClosed :    Boolean <- myfd < 0

	operation unGetChar [r : Character]
	  if minValidIndex > 0 then
	    minValidIndex <- minValidIndex - 1
	    buffer(minValidIndex) := r
	  elseif maxValidIndex < minValidIndex then
	    % the buffer is empty
	    minValidIndex <- 0
	    maxValidIndex <- 0
	    buffer(minValidIndex) := r
	  else
	    returnAndFail
	  end if
	end unGetChar

	operation getChar -> [r : Character]
	  if isClosed then returnAndFail end if
	  if maxValidIndex < minValidIndex then
	    % there is nothing in the buffer
	    if isBroken then
	      maxValidIndex <- ~1
	    else
	      primitive 016 [maxValidIndex] <- [myfd, buffer]
	    end if
	    minValidIndex <- 0
	  end if
	  if maxValidIndex < minValidIndex then
	    isClosed <- true
	    returnAndFail
	  else
	    r <- buffer(minValidIndex)
	    minValidIndex <- minValidIndex + 1
	  end if
	end getChar

	operation getString -> [r : String]
	  var c : Character
	  r <- ""
	  if isClosed then returnAndFail end if
	  loop
	    exit when isClosed
	    if maxValidIndex < minValidIndex then
	      % there is nothing in the buffer
	      if isBroken then
		maxValidIndex <- ~1
	      else
		primitive 016 [maxValidIndex] <- [myfd, buffer]
	      end if
	      minValidIndex <- 0
	    end if
	    if maxValidIndex < minValidIndex then
	      isClosed <- true
	      exit
	    else
	      c <- buffer(minValidIndex)
	      minValidIndex <- minValidIndex + 1
	    end if
	    r <- r || c.asString
	    exit when c = '\^J'
	  end loop
	end getString

	function eos -> [r : Boolean]
	  if isClosed then
	    r <- true
	  else
	    if maxValidIndex < minValidIndex then
	      % there is nothing in the buffer
	      if isBroken then
		maxValidIndex <- ~1
	      else
		primitive 016 [maxValidIndex] <- [myfd, buffer]
	      end if
	      minValidIndex <- 0
	    end if
	    isClosed <- maxValidIndex < minValidIndex
	    r <- isClosed
	  end if
	end eos

	operation close 
	  isClosed <- true
	  maxValidIndex <- ~1
	  primitive 116 [] <- [myfd]
	end close

      end monitor
    end aUnixInStream
  end create
end _InStreamObject
